#This process should be running to keep connection with the controller.
from socket import *
import Queue
import threading
# import thread
import json
import time
import sqlite3
import sys
import socket
import select

sys.path.append("..")

from active_learning import al_init
from crowd_sourcing import label_process
from util.parameter import Para
from active_learning import al_train
from util.RSImageLocation import GetPixelLongitudeAndLatitude
from machine_learning import Classifier

"""
from CaffeProject.active_learning import al_init
from CaffeProject.crowd_sourcing import label_process
from CaffeProject.util.parameter import Para
from CaffeProject.active_learning import al_train
"""


"""
def testGenerateInitializeLabelSamples(rs_name):
    with sqlite3.connect(Para.db_name) as conn:
        values = list()
        for i in range(5):
            temp = (i, 5*i, 5*i, float(31+0.001*i), float(121+0.001*i), -1)
            values.append(temp)
        sql = "insert into %s_label values(?, ?, ?, ?, ?, ?)" % rs_name
        conn.executemany(sql, values)
        conn.commit()
"""


def SendData(data, sock):
    """
    sock.send(data)
    time.sleep(0.05)
    print(str(len(data))+" send OK.")
    """
    bufferSize = 10240
    dataLength = len(data)
    offset = 0
    while offset < dataLength:
        if offset + bufferSize < dataLength:
            sendData = data[offset:offset+bufferSize]
        else:
            sendData = data[offset:]
        sock.send(sendData)
        # print(str(len(sendData)))
        offset += bufferSize
        time.sleep(0.01)
    print(str(len(data))+" send OK.")


def ProcessReceivedData(processing_string, configFileName, sock):
    para = Para(configFileName)
    processing_json = json.loads(processing_string)
    act = str(processing_json["act"])
    if act == "ALInit":
        print("ALInit start.")
        result_string = al_init.ALInitFromController(processing_json, configFileName)
        result_json = json.loads(result_string)
        result_json["act"] = "ALInitResult"
        result_json["sessionId"] = processing_json["sessionId"]
        # fp = open("/root/Qin Yiqing/CaffeProject/sunzy301-CaffeProject-master/CaffeProject/CaffeProject/tmp/"+str(result_json["rs_name"])+".jpg", "rb")
        fp = open(para.tmp + "/" + str(result_json["rs_name"]) + ".jpg", "rb")
        file_data = fp.read(BUFFER_SIZE)
        fp.close()
        result_json["imageSize"] = len(file_data)
        result_string = json.dumps(result_json)
        """
        # test codes begin,generate some label samples
        testGenerateInitializeLabelSamples(str(processing_json["rs_name"]))
        # test codes end
        """
        # sending_queue.put(result_string)
        # sending_queue.put(file_data)
        SendData(result_string, sock)
        SendData(file_data, sock)
        print("ALInit succeeds.")
    if act == "LabelProcess":
        print("LabelProcess start")
        result_json = label_process.LabelProcessFromController(str(processing_json["rs_name"]), configFileName)
        result_json["act"] = "LabelProcessResult"
        result_json["sessionId"] = processing_json["sessionId"]
        fp1 = open(str(result_json["imageDict"]["0"]))
        fp2 = open(str(result_json["imageDict"]["1"]))
        fp3 = open(str(result_json["imageDict"]["2"]))
        fp4 = open(str(result_json["imageDict"]["3"]))
        fp5 = open(str(result_json["imageDict"]["4"]))
        file_data1 = fp1.read(BUFFER_SIZE)
        file_data2 = fp2.read(BUFFER_SIZE)
        file_data3 = fp3.read(BUFFER_SIZE)
        file_data4 = fp4.read(BUFFER_SIZE)
        file_data5 = fp5.read(BUFFER_SIZE)
        fp1.close()
        fp2.close()
        fp3.close()
        fp4.close()
        fp5.close()
        result_json["imageSize0"] = len(file_data1)
        result_json["imageSize1"] = len(file_data2)
        result_json["imageSize2"] = len(file_data3)
        result_json["imageSize3"] = len(file_data4)
        result_json["imageSize4"] = len(file_data5)
        result_string = json.dumps(result_json)
        """
        sending_queue.put(result_string)
        sending_queue.put(file_data1)
        sending_queue.put(file_data2)
        sending_queue.put(file_data3)
        sending_queue.put(file_data4)
        sending_queue.put(file_data5)
        """
        SendData(result_string, sock)
        SendData(file_data1, sock)
        SendData(file_data2, sock)
        SendData(file_data3, sock)
        SendData(file_data4, sock)
        SendData(file_data5, sock)
        print("LabelProcess succeeds.")
    if act == "ReturnLabelResult":
        print("ReturnLabelResult start.")
        labelId = int(processing_json["labelId"])
        rs_name = str(processing_json["rs_name"])
        labelResult = int(processing_json["labelResult"])
        with sqlite3.connect(para.db_name) as conn:
            sql = "update %s_label set label=%i where id=%i" % (rs_name, labelResult, labelId)
            conn.execute(sql)
        print("ReturnLabelResult success")
    if act == "ALTrain":
        print("ALTrain start")
        al_train.ALTrainFromController(processing_string, configFileName)
        print("ALTrain succeeds.")
    if act == "GenerateSample":
        print("GenerateSample start.")
        rs_name = str(processing_json["rs_name"])
        data_file_name = str(processing_json["data_file_name"])
        x = int(processing_json["x"])
        y = int(processing_json["y"])
        labelId = int(processing_json["labelId"])
        labelResult = int(processing_json["labelResult"]);
        longitude, latitude = GetPixelLongitudeAndLatitude(data_file_name, x, y)
        values = list()
        temp = (labelId, x, y, latitude, longitude, labelResult)
        values.append(temp)
        with sqlite3.connect(para.db_name) as conn:
            sql = "insert into %s_label VALUES(?,?,?,?,?,?)" % rs_name
            conn.executemany(sql, values)
        print("GenerateSample succeeds.")
    if act == "Predict":
        print("Predict starts.")
        rs_name = str(processing_json["rs_name"])
        data_file_name = str(processing_json["data_file_name"])
        x = int(processing_json["x"])
        y = int(processing_json["y"])
        labelResult = Classifier.PredictFromController(rs_name, data_file_name, x, y, configFileName)
        resultJson = {}
        resultJson["act"] = "PredictResult"
        resultJson["sessionId"] = processing_json["sessionId"]
        resultJson["labelResult"] = str(int(labelResult))
        resultString = json.dumps(resultJson)
        SendData(resultString, sock)
        print("Predict result:"+str(int(labelResult)))
        print("Predict succeeds.")






configFileName = "/usr/data/remote_sensing/crowdsourcing_label/tmp/para.config"
PORT = 7997
HOST = "10.141.245.186"
ADDR = (HOST, PORT)
BUFFER_SIZE = 4096000


"""
# sending_queue = Queue.Queue(maxsize = 100)
while True:
    try:
        print("Start.")
        sending_queue = Queue.Queue(maxsize = 100)
        # received_queue = Queue.Queue(maxsize = 100)
        # thread.start_new_thread(ProcessReceivedData)
        # process_thread = threading.Thread(target = ProcessReceivedData)
        # process_thread.setDaemon(True)
        # process_thread.start()
        # socket.settimeout = 0.2
        tcp_server_socket = socket.socket(AF_INET, SOCK_STREAM)
        tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        tcp_server_socket.listen(5)
        # Now only one controller is allowed to be connected with model.
        while True:
            sock, addr = tcp_server_socket.accept()
            while True:
                data = sock.recv(4096)
                if not data:
                    break
                else:
                    print(data)
                    ProcessReceivedData(data, configFileName)
                while sending_queue.qsize() > 0:
                    sending_data = sending_queue.get()
                    sock.send(sending_data)
                    print(str(len(sending_data))+" send OK.")
                    time.sleep(0.1)
    except Exception, errorInfo:
        print(errorInfo)
        print("Error")
    finally:
        try:
            tcp_server_socket.shutdown(2)
        except:
            pass
        tcp_server_socket.close()
        time.sleep(1)
"""
socket.setdefaulttimeout(2)
tcp_server_socket = socket.socket(AF_INET, SOCK_STREAM)
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcp_server_socket.bind(ADDR)
tcp_server_socket.listen(5)
inputs = [tcp_server_socket]
while True:
    rs, ws, es = select.select(inputs, [], [])
    for r in rs:
        if r is tcp_server_socket:
            c, addr = tcp_server_socket.accept()
            inputs.append(c)
            print("Connection established.")
        else:
            try:
                data = r.recv(4096)
                disconnected = not data
            except socket.error:
                disconnected = True
            if disconnected:
                inputs.remove(r)
                print("Connection stopped.")
            else:
                print(data)
                try:
                    ProcessReceivedData(data, configFileName, r)
                except Exception, errorInfo:
                    print(errorInfo)
                    inputs.remove(r)